#!/usr/bin/env python
import logging
import multiprocessing
import signal
import os

from tornado.httpclient import AsyncHTTPClient

logging.basicConfig(format='%(levelname)s: %(asctime)s - %(message)s', datefmt='%d.%m.%Y %I:%M:%S')

import django
import sys
from pydicom.uid import *
from pynetdicom import *

os.environ['DJANGO_SETTINGS_MODULE'] = 'neurdicom.settings'
django.setup()

from neurdicom.urls import *
import neurdicom.settings as settings

from tornado.options import options, define, parse_command_line
from apps.dicom_ws.handlers import *
from apps.users.handlers import *
import tornado.httpserver
import tornado.ioloop
import tornado.web
import tornado.wsgi

define('aet', type=str, default='NEURDICOM')
define('rest_port', type=int, default=8080)
define('dicom_port', type=int, default=4242)
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
logger.addHandler(logging.StreamHandler())

rest_app = tornado.web.Application(
    [
        # Users
        (USER_AUTH_URL, UserAuthHandler),
        (USER_CHECK_URL, UserCheckHandler),
        (USER_LOGOUT_URL, UserLogoutHandler),
        (USER_DETAIL_URL, UserDetailHandler),
        (USER_LIST_URL, UserListHandler),

        # Patients
        (PATIENT_STUDIES_URL, PatientStudiesHandler),
        (PATIENT_DETAIL_URL, PatientDetailHandler),
        (PATIENT_LIST_URL, PatientListHandler),

        # Studies
        (STUDY_SERIES_URL, StudySeriesHandler),
        (STUDY_DETAIL_URL, StudyDetailHandler),
        (STUDY_LIST_URL, StudyListHandler),

        # Series
        (SERIES_INSTANCES_URL, SeriesInstancesHandler),
        (SERIES_DETAIL_URL, SeriesDetailHandler),
        (SERIES_LIST_URL, SeriesListHandler),

        # Instances
        (INSTANCE_PROCESS_URL, InstanceProcessHandler),
        (INSTANCE_TAGS_URL, InstanceTagsHandler),
        (INSTANCE_IMAGE_URL, InstanceImageHandler),
        (INSTANCE_RAW_URL, InstanceRawHandler),
        (INSTANCE_DETAIL_URL, InstanceDetailHandler),
        (INSTANCE_LIST_URL, InstanceListHandler),
        (INSTANCE_UPLOAD_URL, InstanceUploadHandler),

        # Dicom Nodes
        (DICOM_NODE_DETAIL_URL, DicomNodeDetailHandler),
        (DICOM_NODE_LIST_URL, DicomNodeListHandler),
        # (DICOM_NODE_ECHO_URL, DicomNodeEchoHandler),
        (DICOM_NODE_INSTANCES_URL, DicomNodeInstancesLoadHandler),

        # Plugins
        (PLUGIN_DETAIL_URL, PluginDetailHandler),
        (PLUGIN_LIST_URL, PluginListHandler),
        (PLUGIN_INSTALL_URL, InstallPluginHandler),

        # Media download
        (MEDIA_URL, tornado.web.StaticFileHandler, {'path': 'media'})
    ], cookie_secret=settings.SECRET_KEY)


def start_dicom_server():
    try:
        logger.info('DICOM server starting at port = %d' % settings.DICOM_SERVER['port'])
        dicom_server = DICOMServer(ae_title=settings.DICOM_SERVER['aet'])

        dicom_server.supported_contexts = StoragePresentationContexts + VerificationPresentationContexts
        for transferSyntaxes in UncompressedPixelTransferSyntaxes:
            dicom_server.add_requested_context(transferSyntaxes)
        address = (settings.DICOM_SERVER['host'], settings.DICOM_SERVER['port'])
        dicom_server.start_server(address=address)
    except (KeyboardInterrupt, SystemExit):
        logger.info('DICOM server finishing...')
        logger.info('Child process exiting...')
        sys.exit(0)


def start_rest_server():
    try:
        rest_port = options.rest_port or settings.DICOMWEB_SERVER['port']
        rest_server = tornado.httpserver.HTTPServer(rest_app)
        rest_server.bind(rest_port)
        rest_server.start()
        logger.info('Rest server starting at port = %d' % settings.DICOMWEB_SERVER['port'])
        tornado.ioloop.IOLoop.current().start()
    except (KeyboardInterrupt, SystemExit):
        logger.info('Rest server finishing...')
        os.kill(os.getpid(), signal.SIGINT)
        logger.info('Parent process exiting...')
        sys.exit(0)


def main():
    parse_command_line()
    if not settings.RUN_DICOM:
        return start_rest_server()

    dicom_process = multiprocessing.Process(target=start_dicom_server)
    rest_process = multiprocessing.Process(target=start_rest_server)

    dicom_process.start()
    rest_process.start()

    try:
        dicom_process.join()
        rest_process.join()
    except (KeyboardInterrupt, SystemExit):
        logger.info('Main process handling interruption...')
        dicom_process.terminate()
        rest_process.terminate()
        dicom_process.join()
        rest_process.join()
        logger.info('All processes are finished')


if __name__ == '__main__':
    main()
